/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2010-2014, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "sys_inc.h"
#include "xml_node.h"
#include "hxml.h"

/***************************************************************************************/
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
#define IS_XMLH_START(ptr) (*ptr == '<' && *(ptr+1) == '?')
#define IS_XMLH_END(ptr) (*ptr == '?' && *(ptr+1) == '>')

/***************************************************************************************/
/**
 * 把parse->ptr指向第一行末尾
 *
 * @param parse LTXMLPRS地址
 @return 0 on success, -1 otherwise
 */

// <?xml version="1.0" encoding="UTF-8"?>
int hxml_parse_header(LTXMLPRS * parse)
{
	char * ptr = parse->ptr;
	char * xmlend = parse->xmlend;

	while(IS_WHITE_SPACE(*ptr) && (ptr != xmlend)) ptr++;
	if(ptr == xmlend) return -1;

	if(!IS_XMLH_START(ptr))
		return -1;
	ptr+=2;
	while((!IS_XMLH_END(ptr)) && (ptr != xmlend)) ptr++;
	if(ptr == xmlend) return -1;
	ptr+=2;
	parse->ptr = ptr;

	return 0;
}

/***************************************************************************************/
#define IS_ELEMS_END(ptr) (*ptr == '>' || (*ptr == '/' && *(ptr+1) == '>'))
#define IS_ELEME_START(ptr) (*ptr == '<' && *(ptr+1) == '/')

#define RF_NO_END		0
#define RF_ELES_END		2
#define RF_ELEE_END		3

/***************************************************************************************/
/**
 * 
 *
 * @param 
 * @return 
 */
int hxml_parse_attr(LTXMLPRS * parse)
{
	char * ptr = parse->ptr;
	char * xmlend = parse->xmlend;
	int ret = RF_NO_END;
	int cnt = 0;

	while(1)
	{
		ret = RF_NO_END;

		while(IS_WHITE_SPACE(*ptr) && (ptr != xmlend)) ptr++;
		if(ptr == xmlend) return -1;

		if(*ptr == '>')
		{
			*ptr = '\0'; ptr++;
			ret = RF_ELES_END; // node start finish
			break;
		}
		else if(*ptr == '/' && *(ptr+1) == '>')
		{
			*ptr = '\0'; ptr += 2;
			ret = RF_ELEE_END;	// node end finish
			break;
		}

		char * attr_name = ptr;
		while(*ptr != '=' && (!IS_ELEMS_END(ptr)) && ptr != xmlend) ptr++;
		if(ptr == xmlend) return -1;
		if(IS_ELEMS_END(ptr))
		{
			if(*ptr == '>')
			{
				ret = RF_ELES_END;
				*ptr = '\0'; ptr++;
			}
			else if(*ptr == '/' && *(ptr+1) == '>')
			{
				ret = RF_ELEE_END;
				*ptr = '\0'; ptr+=2;
			}
			break;
		}

		*ptr = '\0';	// '=' --> '\0'
		ptr++;

		char * attr_value = ptr;
		if(*ptr == '"')
		{
			attr_value++;
			ptr++;
			while(*ptr != '"' && ptr != xmlend) ptr++;
			if(ptr == xmlend) return -1;
			*ptr = '\0'; // '"' --> '\0'

			ptr++;
		}
		else
		{
			while((!IS_WHITE_SPACE(*ptr)) && (!IS_ELEMS_END(ptr)) && ptr != xmlend) ptr++;
			if(ptr == xmlend) return -1;

			if(IS_WHITE_SPACE(*ptr))
			{
				*ptr = '\0';
				ptr++;
			}
			else
			{
				if(*ptr == '>')
				{
					ret = RF_ELES_END;
					*ptr = '\0'; ptr++;
				}
				else if(*ptr == '/' && *(ptr+1) == '>')
				{
					ret = RF_ELEE_END;
					*ptr = '\0'; ptr+=2;
				}
			}
		}

		int index = cnt << 1;
		parse->attr[index] = attr_name;
		parse->attr[index+1] = attr_value;
		cnt++;
		if(ret > RF_NO_END)
			break;
	}

	parse->ptr = ptr;
	return ret;
}

#define CHECK_XML_STACK_RET(parse) \
	do{ if(parse->e_stack_index >= LTXML_MAX_STACK_DEPTH || parse->e_stack_index < 0) return -1;}while(0)

int hxml_parse_element_end(LTXMLPRS * parse)
{
	char * stack_name = parse->e_stack[parse->e_stack_index];
	if(stack_name == NULL)
		return -1;

	char * xmlend = parse->xmlend;

	while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++;
	if((parse->ptr) == xmlend) return -1;

	char * end_name = (parse->ptr);
	while((!IS_WHITE_SPACE(*(parse->ptr))) && ((parse->ptr) != xmlend) && (*(parse->ptr) != '>')) (parse->ptr)++;
	if((parse->ptr) == xmlend) return -1;
	if(IS_WHITE_SPACE(*(parse->ptr)))
	{
		*(parse->ptr) = '\0'; (parse->ptr)++;
		while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++;
		if((parse->ptr) == xmlend) return -1;
	}

	if(*(parse->ptr) != '>') return -1;
	*(parse->ptr) = '\0';
	(parse->ptr)++;

	if(strcasecmp(end_name, stack_name) != 0)
	{
		printf("hxml_parse_element_end::cur name[%s] != stack name[%s]!!!\r\n", end_name, stack_name);
		return -1;
	}

	if(parse->endElement)
		parse->endElement(parse->userdata, end_name);

	parse->e_stack[parse->e_stack_index] = NULL; parse->e_stack_index--;
	CHECK_XML_STACK_RET(parse);

	return 0;
}

int hxml_parse_element_start(LTXMLPRS * parse)
{
	char * xmlend = parse->xmlend;

	//去空格
	while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++;
	if((parse->ptr) == xmlend) return -1;

	//找到空格或者结尾
	char * element_name = (parse->ptr);
	while((!IS_WHITE_SPACE(*(parse->ptr))) && ((parse->ptr) != xmlend) && (!IS_ELEMS_END((parse->ptr)))) (parse->ptr)++;
	if((parse->ptr) == xmlend) return -1;

	parse->e_stack_index++; parse->e_stack[parse->e_stack_index] = element_name;
	CHECK_XML_STACK_RET(parse);

	if(*(parse->ptr) == '>')
	{
		*(parse->ptr) = '\0'; (parse->ptr)++;
		if(parse->startElement)
			parse->startElement(parse->userdata, element_name, parse->attr);
		return RF_ELES_END;
	}
	else if(*(parse->ptr) == '/' && *((parse->ptr)+1) == '>')
	{
		*(parse->ptr) = '\0'; (parse->ptr)+=2;
		if(parse->startElement)
			parse->startElement(parse->userdata, element_name, parse->attr);
		if(parse->endElement)
			parse->endElement(parse->userdata, element_name);

		parse->e_stack[parse->e_stack_index] = NULL; parse->e_stack_index--;
		CHECK_XML_STACK_RET(parse);
		return RF_ELEE_END;
	}
	else
	{
		*(parse->ptr) = '\0'; (parse->ptr)++;

		int ret = hxml_parse_attr(parse); if(ret < 0) return -1;

		if(parse->startElement)
			parse->startElement(parse->userdata, element_name, parse->attr);

		memset(parse->attr, 0, sizeof(parse->attr));

		if(ret == RF_ELEE_END)
		{
			if(parse->endElement)
				parse->endElement(parse->userdata, element_name);

			parse->e_stack[parse->e_stack_index] = NULL; parse->e_stack_index--;
			CHECK_XML_STACK_RET(parse);
		}

		return ret;
	}
}

#define CUR_PARSE_START		1
#define CUR_PARSE_END		2

int hxml_parse_element(LTXMLPRS * parse)
{
	char * xmlend = parse->xmlend;
	int parse_type = CUR_PARSE_START;
	while(1)
	{
		int ret = RF_NO_END;

xml_parse_type:
        //跳过空格
		while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++;
		if((parse->ptr) == xmlend)
		{
			if(parse->e_stack_index == 0)
				return 0;
			return -1;
		}


		//</ 开头，结尾
		if(*(parse->ptr) == '<' && *((parse->ptr)+1) == '/')
		{
			(parse->ptr)+=2;
			parse_type = CUR_PARSE_END;
		}
		//< 开头，开始
		else if(*(parse->ptr) == '<')
		{
			(parse->ptr)++;
			parse_type = CUR_PARSE_START;
		}
		else
		{
			return -1;
		}

//xml_parse_point:

		//跳过空格
		while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++;
		if((parse->ptr) == xmlend)
		{
			if(parse->e_stack_index == 0)
				return 0;
			return -1;
		}

		if(parse_type == CUR_PARSE_END)
		{
			ret = hxml_parse_element_end(parse);
			if(ret < 0)
				return -1;

			if(parse->e_stack_index == 0)
				return 0;

			parse_type = CUR_PARSE_START;
		}
		else // CUR_PARSE_START
		{
			ret = hxml_parse_element_start(parse);
			if(ret < 0)
				return -1;
			if(ret == RF_ELEE_END)
			{
				if(parse->e_stack_index == 0)
					return 0;

				parse_type = CUR_PARSE_START;
				goto xml_parse_type;
			}

			while(IS_WHITE_SPACE(*(parse->ptr)) && ((parse->ptr) != xmlend)) (parse->ptr)++; 
			if((parse->ptr) == xmlend) return -1;
			
			if(*(parse->ptr) == '<') goto xml_parse_type; 

			char * cdata_ptr = (parse->ptr);
			while(*(parse->ptr) != '<' && (parse->ptr) != xmlend) (parse->ptr)++;
			if((parse->ptr) == xmlend) return -1;

			int len = (parse->ptr) - cdata_ptr;
			if(len > 0)	
			{
				*(parse->ptr) = '\0'; (parse->ptr)++;
				if(parse->charData)
					parse->charData(parse->userdata, cdata_ptr, len);

				if(*(parse->ptr) != '/')
					return -1;

				(parse->ptr)++;

				if(hxml_parse_element_end(parse) < 0)
					return -1;
			}

			goto xml_parse_type;
		}
	}

	return 0;
}

int hxml_parse(LTXMLPRS * parse)
{
	// printf("hxml parse header start...\r\n");
	int ret =  hxml_parse_header(parse);
	if(ret < 0)
	{
		// printf("hxml parse xml header failed!!!\r\n");
		// return -1;
	}

	// printf("hxml parse element start...\r\n");
	return hxml_parse_element(parse);
}

void xml_startElement(void * userdata, const char * name, const char ** attr)
{
	printf("startElement[%s].\r\n", name);
	int i;
	for(i=0; ;i++)
	{
		if(attr[i] && attr[i+1])
			printf("\tattr[%s]=[%s].\r\n", attr[i], attr[i+1]);
		else
			break;
	}
}

void xml_endElement(void * userdata, const char * name)
{
	printf("endElement[%s].\r\n", name);
}

void xml_charData(void * userdata, const char * str, int len)
{
	printf("charData[%s].\r\n", str);
}




